"""
钩子中心
提供"事件-订阅"机制，支持同步/异步钩子
"""

import asyncio
import json
import os
from typing import Any, Callable, Dict, List, Optional, Union
from collections import defaultdict
import logging


class HookSubscriber:
    """钩子订阅者"""
    
    def __init__(
        self,
        callback: Callable[..., Any],
        priority: int = 0,
        is_async: bool = False
    ) -> None:
        self.callback = callback
        self.priority = priority
        self.is_async = is_async
    
    def __lt__(self, other: 'HookSubscriber') -> bool:
        # 优先级高的排在前面（数字越大优先级越高）
        return self.priority > other.priority


class HookHub:
    """
    钩子中心
    
    提供事件订阅和发布机制：
    - 支持同步和异步钩子
    - 支持优先级排序
    - 支持持久化订阅关系
    - 支持事件拦截和取消
    """
    
    def __init__(self, persistence_file: Optional[str] = None) -> None:
        self._hooks: Dict[str, List[HookSubscriber]] = defaultdict(list)
        self._logger = logging.getLogger(__name__)
        self._persistence_file = persistence_file
        
        # 如果指定持久化文件，加载订阅关系
        if persistence_file and os.path.exists(persistence_file):
            self._load_persistence()
    
    def register(
        self,
        event: str,
        callback: Callable[..., Any],
        priority: int = 0,
        is_async: bool = False
    ) -> None:
        """
        注册事件订阅
        
        Args:
            event: 事件名称
            callback: 回调函数
            priority: 优先级（数字越大越先执行）
            is_async: 是否异步回调
        """
        subscriber = HookSubscriber(callback, priority, is_async)
        self._hooks[event].append(subscriber)
        # 按优先级排序
        self._hooks[event].sort()
        
        self._logger.debug(f"Registered hook: {event}, priority: {priority}")
        
        # 持久化
        if self._persistence_file:
            self._save_persistence()
    
    def unregister(self, event: str, callback: Callable[..., Any]) -> bool:
        """
        注销事件订阅
        
        Args:
            event: 事件名称
            callback: 回调函数
            
        Returns:
            是否注销成功
        """
        if event not in self._hooks:
            return False
        
        original_len = len(self._hooks[event])
        self._hooks[event] = [
            sub for sub in self._hooks[event]
            if sub.callback != callback
        ]
        
        success = len(self._hooks[event]) < original_len
        
        if success:
            self._logger.debug(f"Unregistered hook: {event}")
            if self._persistence_file:
                self._save_persistence()
        
        return success
    
    def emit(self, event: str, **kwargs: Any) -> List[Any]:
        """
        触发同步事件
        
        Args:
            event: 事件名称
            **kwargs: 事件参数
            
        Returns:
            所有回调的返回值列表
        """
        if event not in self._hooks:
            return []
        
        results = []
        for subscriber in self._hooks[event]:
            if subscriber.is_async:
                self._logger.warning(
                    f"Skip async hook in sync emit: {event}"
                )
                continue
            
            try:
                result = subscriber.callback(**kwargs)
                results.append(result)
                
                # 如果返回False，停止传播
                if result is False:
                    self._logger.debug(f"Event propagation stopped: {event}")
                    break
            except Exception as e:
                self._logger.error(
                    f"Hook callback error [{event}]: {e}",
                    exc_info=True
                )
        
        return results
    
    async def emit_async(self, event: str, **kwargs: Any) -> List[Any]:
        """
        触发异步事件
        
        Args:
            event: 事件名称
            **kwargs: 事件参数
            
        Returns:
            所有回调的返回值列表
        """
        if event not in self._hooks:
            return []
        
        results = []
        for subscriber in self._hooks[event]:
            try:
                if subscriber.is_async:
                    result = await subscriber.callback(**kwargs)
                else:
                    result = subscriber.callback(**kwargs)
                
                results.append(result)
                
                # 如果返回False，停止传播
                if result is False:
                    self._logger.debug(f"Event propagation stopped: {event}")
                    break
            except Exception as e:
                self._logger.error(
                    f"Hook callback error [{event}]: {e}",
                    exc_info=True
                )
        
        return results
    
    def has_subscribers(self, event: str) -> bool:
        """检查事件是否有订阅者"""
        return event in self._hooks and len(self._hooks[event]) > 0
    
    def get_subscribers_count(self, event: str) -> int:
        """获取事件订阅者数量"""
        return len(self._hooks.get(event, []))
    
    def clear_event(self, event: str) -> None:
        """清除事件的所有订阅"""
        if event in self._hooks:
            del self._hooks[event]
            self._logger.debug(f"Cleared all hooks for event: {event}")
    
    def clear_all(self) -> None:
        """清除所有订阅"""
        self._hooks.clear()
        self._logger.debug("Cleared all hooks")
    
    def get_events(self) -> List[str]:
        """获取所有已注册的事件名称"""
        return list(self._hooks.keys())
    
    # ========== 持久化 ==========
    
    def _save_persistence(self) -> None:
        """保存订阅关系到文件（仅保存元数据，不保存函数）"""
        if not self._persistence_file:
            return
        
        # 只保存事件名称和订阅数量（函数无法序列化）
        data = {
            event: len(subscribers)
            for event, subscribers in self._hooks.items()
        }
        
        try:
            with open(self._persistence_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=2)
        except Exception as e:
            self._logger.error(f"Failed to save hook persistence: {e}")
    
    def _load_persistence(self) -> None:
        """加载持久化数据（仅作记录）"""
        if not self._persistence_file:
            return
        
        try:
            with open(self._persistence_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
            self._logger.info(f"Loaded hook metadata: {data}")
        except Exception as e:
            self._logger.error(f"Failed to load hook persistence: {e}")